package com.zhenxiang.interceptor;

import com.alibaba.fastjson.JSON;
import com.zhenxiang.common.api.ApiResult;
import com.zhenxiang.utils.GenerateSignatureUtil;
import com.zhenxiang.utils.ServletUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author 真香
 * @Date 2021/4/20 15:53
 * @Version 1.0
 */
@Slf4j
public class SignAuthInterceptor implements HandlerInterceptor {
    private static final String NONCE_KEY_STR = "nonce-";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        Map<String, String[]> map = request.getParameterMap();
        // 从数组中取出参数放入Map中
        Map<String,String> param = new ConcurrentHashMap<>(10);
        for (Map.Entry<String, String[]> entry  : map.entrySet()) {
            String key = entry.getKey();
            String[] values = entry.getValue();
            for (int i = 0; i < values.length; i++) {
                String value = values[i];
                param.put(key,value);
            }
        }
        //  1、获取请求参数appId
        String appid = param.get("appid");
        if (StringUtils.isBlank(appid)) {
            log.info("appid不能为空");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("appid不能为空")));
            return false;
        }

        // 2、获取请求参数secret
        String secret =request.getParameter("secret");
        if (StringUtils.isBlank(secret)){
            log.info("secret不能为空...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("secret不能为空")));
            return false;
        }

        /** 3、验证secret权限、来源是否合法
         *  此处可以用appId,条件为 已开启，未封禁等进行数据库合作机构表查询，有可能已经终止合作禁止了此有用访问,
         *  业务上达到一定条件的可以根据appId分配权限，选择不同的接口能力进行开放
         */
       /* TDrivingCooperation drivingCooperationByPartnerkey = drivingCooperationService.getDrivingCooperationByPartnerkey(partnerkey);
        if (drivingCooperationByPartnerkey == null || drivingCooperationByPartnerkey.getStatus().equals(StatusEnum.DISABLE.getCode())) {
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("partnerkey无法查询到合作公司信息或已被封禁")));
            return false;
        }*/
        // 获取secret 与数据库值对比，判断请求来源是否合法
       /* if (!secret.equals(drivingCooperationByPartnerkey.getSecret())) {
            log.debug("secret与接口提供方不一致...........");
            System.out.println("secret与接口提供方不一致...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("secret与接口提供方不一致")));
            return false;
        }*/

        // 4、 获取请求参数timestamp 时间戳，
        String timestamp = request.getParameter("timestamp");
        if (StringUtils.isBlank(timestamp)){
            log.info("timestamp不能为空...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("timestamp不能为空")));
            return false;
        }

        /** 5、 防止过期时间的提交
         * 从前端传递的timestamp 与服务器端当前系统时间之差大于120s，则此次请求的timestamp无效
         *  留出短时间考虑网络问题提交速度慢，若时间过长中间时间足以挟持篡改参数，所以折中考虑了120秒
         */
        Long time = System.currentTimeMillis()/1000;
        if (Math.abs(Long.valueOf(timestamp)-time)>120) {
            log.info("timestamp失效...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("timestamp失效")));
            return false;
        }

        // 6、获取请求参数nonce随机数，防止重复的暴力请求
        String nonce = param.get("nonce");
        if (StringUtils.isBlank(nonce)) {
            log.debug("nonce不能为空...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("nonce不能为空")));
            return false;
        }
        /**
         *  如果设计得规范一些可以防止重复提交，我这因为是小项目，Demo演示就不做redis缓存随机数了
         *   流程：1、获取当前提交的随机数，作为key前往redis 查询，若有值则为重复提交
         *         2、redis中查询不到结果，将当前随机数作为key，value为随机数，过期时间设置为120s
         */
        // 7、获取请求sign签名参数，
        String sign = param.get("sign");
        if (StringUtils.isBlank(sign)){
            log.info("sign不能为空...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("sign不能为空")));
            return false;
        }
        //8.通过后台MD5重新签名校验与前端签名sign值比对，确认当前请求数据是否被篡改
        boolean reuslt = GenerateSignatureUtil.isSignatureValid(param, secret);
        if (!reuslt){
            log.debug("sign签名校验失败...........");
            ServletUtils.renderString(response, JSON.toJSONString(ApiResult.failRequest("sign签名校验失败")));
            return false;
        }
        log.info("签名校验通过，放行...........");
        // 获取sign签名，与服务端生成的sign 签名对比
        System.out.println("sign ====================");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("SignAuthInterceptor postHandle======  ");
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("SignAuthInterceptor afterCompletion======  ");
    }
}
